package main

import (
	"encoding/json"
	"fmt"
	"log"
	"strconv"
	"time"

	"go.etcd.io/bbolt"
)

// ReportData 定义上报数据结构
type ReportData struct {
	ID          int    `json:"id"`
	ServiceName string `json:"service_name"`
	DeviceName  string `json:"device_name"`
	Data        string `json:"data"`
	ReportFlag  bool   `json:"report_flag"`
}

// 数据库文件路径
const dbPath = "report_queue.db"

// 队列对应的 bucket 名称
const queueBucket = "report_queue"

// 打开或创建 bbolt 数据库
func openDB() (*bbolt.DB, error) {
	return bbolt.Open(dbPath, 0755, nil)
}

// 向队列中添加数据
func enqueue(db *bbolt.DB, data ReportData) error {
	return db.Update(func(tx *bbolt.Tx) error {
		// 创建队列 bucket
		bucket, err := tx.CreateBucketIfNotExists([]byte(queueBucket))
		if err != nil {
			return err
		}

		// 使用当前时间戳（纳秒）作为键
		key := strconv.FormatInt(time.Now().UnixNano(), 10)

		// 序列化数据为 JSON
		value, err := json.Marshal(data)
		if err != nil {
			return err
		}

		// 将数据写入 bucket
		return bucket.Put([]byte(key), value)
	})
}

// 从队列中获取并移除最早插入的数据（出队操作）
func dequeue(db *bbolt.DB) (*ReportData, error) {
	var report ReportData

	err := db.Update(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket([]byte(queueBucket))
		if bucket == nil {
			return fmt.Errorf("队列 bucket '%s' 不存在", queueBucket)
		}

		// 获取队列中最早的键值对
		cursor := bucket.Cursor()
		key, value := cursor.First()
		if key == nil {
			return fmt.Errorf("队列为空")
		}

		// 反序列化 JSON 数据
		if err := json.Unmarshal(value, &report); err != nil {
			return err
		}

		// 移除该键值对
		return bucket.Delete(key)
	})

	if err != nil {
		return nil, err
	}

	return &report, nil
}

// 查看队列中的所有数据（仅用于调试）
func viewQueue(db *bbolt.DB) error {
	return db.View(func(tx *bbolt.Tx) error {
		bucket := tx.Bucket([]byte(queueBucket))
		if bucket == nil {
			return fmt.Errorf("队列 bucket '%s' 不存在", queueBucket)
		}

		// 遍历所有键值对
		fmt.Println("当前队列内容：")
		return bucket.ForEach(func(k, v []byte) error {
			var report ReportData
			if err := json.Unmarshal(v, &report); err != nil {
				return err
			}
			fmt.Printf("Key: %s, Value: %+v\n", k, report)
			return nil
		})
	})
}

// 示例调用
func main() {
	db, err := openDB()
	if err != nil {
		log.Fatalf("打开数据库失败: %v", err)
	}
	defer db.Close()

	// 向队列中添加数据
	data1 := ReportData{
		ID:          int(time.Now().Unix()),
		ServiceName: "ServiceA",
		DeviceName:  "DeviceX",
		Data:        "TestData1",
		ReportFlag:  true,
	}
	data2 := ReportData{
		ID:          int(time.Now().Unix()+1),
		ServiceName: "ServiceB",
		DeviceName:  "DeviceY",
		Data:        "TestData2",
		ReportFlag:  false,
	}

	if err := enqueue(db, data1); err != nil {
		log.Fatalf("数据入队失败: %v", err)
	}
	if err := enqueue(db, data2); err != nil {
		log.Fatalf("数据入队失败: %v", err)
	}
	fmt.Println("数据入队完成")

	// 查看队列内容
	if err := viewQueue(db); err != nil {
		log.Fatalf("查看队列失败: %v", err)
	}

	// 从队列中出队
	dequeuedData, err := dequeue(db)
	if err != nil {
		log.Fatalf("数据出队失败: %v", err)
	}
	fmt.Printf("出队数据: %+v\n", dequeuedData)

	// 再次查看队列内容
	if err := viewQueue(db); err != nil {
		log.Fatalf("查看队列失败: %v", err)
	}
}
